import os
from os import sys
import cleanpoly
from ctypes import *

class ConvProvider:
    def convert (self, FilePath1, FilePath2, bTessellation = False):
        
        filename1, fileext1 = os.path.splitext(FilePath1)
        filename2, fileext2 = os.path.splitext(FilePath2)
        #
        self.InputFile = FilePath1
        self.OutputFile = FilePath2
        # data storage
        self.vert_list = []
        self.face_list = []
        #tessellation
        self.bTessellation = bTessellation
        #
        if (fileext1 == fileext2 and bTessellation == False):
            #prevent from tessellating
            print("the same input and output")
            return
        else:
            # data IO
            if fileext1 == '.obj':
                self.__ReadObj()
            else:
                self.__ReadPoly()
            if fileext2 == '.obj':
                self.__WriteObj()
            else:
                self.__WritePoly()

#private members
    #read OBJ file and tessellate ()
    def __ReadObj(self):
        try:
            f_obj = file(self.InputFile, 'r')
        except:
            print ("Invalide file: " + self.InputFile)
            return False
        #read vertics and faces
        for line in f_obj:
            if line.startswith('v') and line[1] == ' ':
                line = line[1:-1].strip()
                self.vert_list.append(map(float, line.split(' ')))
            elif line.startswith('f') and line[1] == ' ':
                index_list = []
                #to filter out the /
                for index in line[1:-1].strip().split(' '):
                    index_list.append(index.split('/')[0])
                #tesselation for polygon (more than 3 vertices)
                if self.bTessellation and len(index_list) > 3:
                    #workaround
                    curr_dir_before = os.getcwd()
                    path = os.path.dirname(os.path.realpath(__file__))
                    if sizeof(c_voidp) == 4:
                        path += '\\x32'
                        os.chdir(path)
                        Tessellator = CDLL('tesselatorInterface.dll')
                    elif sizeof(c_voidp) == 8:
                        #workaround 
                        path += '\\x64'
                        os.chdir(path)
                        Tessellator = CDLL('tesselatorInterface.dll')
                    os.chdir(curr_dir_before)
                    #add rings
                    ring_vert_num = len(index_list)
                    ExtRingCoords = (c_double * 3 * ring_vert_num)()
                    for j in range(0, ring_vert_num):
                        ExtRingCoords[j][0] = self.vert_list[int(index_list[j])-1][0]
                        ExtRingCoords[j][1] = self.vert_list[int(index_list[j])-1][1]
                        ExtRingCoords[j][2] = self.vert_list[int(index_list[j])-1][2]
                    Tessellator.AddRing(pointer(ExtRingCoords), ring_vert_num, c_bool(1))
                    #compute
                    OutputVerNum = c_int(0)
                    OutputIndiceNum = c_int(0)
                    if Tessellator.Tessellation(byref(OutputVerNum), byref(OutputIndiceNum)) == c_bool(0):
                        print "Tesselation failed"
                    #output
                    OutputCoords = (c_double * 3 * OutputVerNum.value)()
                    OutputIndices = (c_int * 3 * OutputIndiceNum.value)()
                    Tessellator.Output(pointer(OutputCoords), pointer(OutputIndices))
                    #convert indices
                    if ring_vert_num != OutputVerNum.value:
                        print ('intersection existed')
                    OutputCoordsIndice = [] #the indices of the outputverts
                    for j in range (0, OutputVerNum.value):
                        vert = OutputCoords[j]
                        vert = [OutputCoords[j][0], OutputCoords[j][1], OutputCoords[j][2]]
                        try:
                            k = self.vert_list.index(vert)
                        except ValueError:
                            k = len(self.vert_list)
                            self.vert_list.append(vert)
                            print ('Vertex '+ str(k) + ' added')
                        OutputCoordsIndice.append(k)
                    #Add to face_list
                    for j in range (0, OutputIndiceNum.value):
                        self.face_list.append([OutputCoordsIndice[OutputIndices[j][0]],OutputCoordsIndice[OutputIndices[j][1]],OutputCoordsIndice[OutputIndices[j][2]]])
                else:
                    #index - 1
                    index_list = [int(i)-1 for i in index_list]
                    self.face_list.append(index_list)

        #check the content
        if self.vert_list.count == 0 or self.face_list.count == 0:
            print "Invalid Obj file!\n"
        f_obj.close()
    #end __ReadObj
    
    #read OBJ file and try to tessellate
    def __ReadPoly(self):
        #first clean the poly file (code from Hugo Ledoux)
        try:
            cleanpoly.CleanPoly(self.InputFile, self.InputFile + "mid")
        except:
            print ("Cleanpoly failed")
        #then
        try:
            f_poly = file(self.InputFile + "mid" , 'r')
        except:
            print ("Invalide file:" + "..\Output.polymid")
            sys.exit()
        #read
        line_list = []

        #vertices
        f_line = f_poly.readline()
        while f_line.startswith('#'):
            f_line = f_poly.readline()

        f_line = f_line[:-1].strip()
        line_list = f_line.split(' ')
        vert_no = int(line_list[0])
        for i in range (0, vert_no):
            line_list = []
            f_line = f_poly.readline()
            f_line = f_line[:-1].strip()
            line_list.append(map(float, f_line.split(' ')[-3:]))
            self.vert_list.append(line_list[0])

        #faces
        f_line = f_poly.readline()
        line_list = []
        f_line = f_line[:-1].strip()
        line_list.append(map(int, f_line.split(' ')))
        face_no = int(line_list[0][0])
        for i in range (0, face_no):
            line_list = []
            f_line = f_poly.readline()
            f_line = f_line[:-1].strip()
            line_list = f_line.split(' ')
            ring_no = int(line_list[0][0])
            #extior ring
            line_list = []
            f_line = f_poly.readline()
            f_line = f_line[:-1].strip()
            line_list.append(map(int, f_line.split(' ')))
            #if contain holes then do triangulation
            #read rings
            if ring_no > 1:
                nTotalVerts = line_list[0][0]
                for j in range (1, ring_no):
                    #interior ring
                    f_line = f_poly.readline()
                    f_line = f_line[:-1].strip()
                    line_list.append(map(int, f_line.split(' ')))
                    nTotalVerts = nTotalVerts + line_list[j][0]
                    #hole skipped
                    f_line = f_poly.readline()
                #workaround
                curr_dir_before = os.getcwd()
                path = os.path.dirname(os.path.realpath(__file__))
                if sizeof(c_voidp) == 4:
                    path += '\\x32'
                    os.chdir(path)
                    Tessellator = CDLL('tesselatorInterface.dll')
                elif sizeof(c_voidp) == 8:
                    #workaround 
                    path += '\\x64'
                    os.chdir(path)
                    Tessellator = CDLL('tesselatorInterface.dll')
                os.chdir(curr_dir_before)
                #add rings
                ExtRingCoords = (c_double * 3 * line_list[0][0] )()
                for j in range(0, line_list[0][0]):
                    ExtRingCoords[j][0] = self.vert_list[line_list[0][j+1]][0]
                    ExtRingCoords[j][1] = self.vert_list[line_list[0][j+1]][1]
                    ExtRingCoords[j][2] = self.vert_list[line_list[0][j+1]][2]
                Tessellator.AddRing(pointer(ExtRingCoords), line_list[0][0], c_bool(1))

                for j in range (0, ring_no-1):
                    IntRingCoords = ((c_double * 3) * line_list[j+1][0])()
                    for k in range (0, line_list[j+1][0]):
                        IntRingCoords[k][0] = self.vert_list[line_list[j+1][k+1]][0]
                        IntRingCoords[k][1] = self.vert_list[line_list[j+1][k+1]][1]
                        IntRingCoords[k][2] = self.vert_list[line_list[j+1][k+1]][2]
                    Tessellator.AddRing(pointer(IntRingCoords), line_list[j+1][0], c_bool(0))
                 
                #compute
                OutputVerNum = c_int(0)
                OutputIndiceNum = c_int(0)
                if Tessellator.Tessellation(byref(OutputVerNum), byref(OutputIndiceNum)) == c_bool(0):
                    print "Tesselation failed"
                #output
                OutputCoords = (c_double * 3 * OutputVerNum.value)()
                OutputIndices = (c_int * 3 * OutputIndiceNum.value)()
                Tessellator.Output(pointer(OutputCoords), pointer(OutputIndices))
                #convert indices
                if nTotalVerts != OutputVerNum.value:
                    print ('intersection existed')
                OutputCoordsIndice = [] #the indices of the outputverts
                for j in range (0, OutputVerNum.value):
                    vert = [OutputCoords[j][0], OutputCoords[j][1], OutputCoords[j][2]]
                    try:
                        k = self.vert_list.index(vert)
                    except ValueError:
                        k = len(self.vert_list)
                        self.vert_list.append(vert)
                        print ('Vertex '+ str(k) + ' added')
                    OutputCoordsIndice.append(k)
                #Add to face_list
                for j in range (0, OutputIndiceNum.value):
                    self.face_list.append([OutputCoordsIndice[OutputIndices[j][0]],OutputCoordsIndice[OutputIndices[j][1]],OutputCoordsIndice[OutputIndices[j][2]]])
            elif self.bTessellation == True and line_list[0][0] > 3:
                #workaround
                curr_dir_before = os.getcwd()
                path = os.path.dirname(os.path.realpath(__file__))
                if sizeof(c_voidp) == 4:
                    path += '\\x32'
                    os.chdir(path)
                    Tessellator = CDLL('tesselatorInterface.dll')
                elif sizeof(c_voidp) == 8:
                    #workaround 
                    path += '\\x64'
                    os.chdir(path)
                    Tessellator = CDLL('tesselatorInterface.dll')
                os.chdir(curr_dir_before)
                #add rings
                ExtRingCoords = (c_double * 3 * line_list[0][0] )()
                for j in range(0, line_list[0][0]):
                    ExtRingCoords[j][0] = self.vert_list[line_list[0][j+1]][0]
                    ExtRingCoords[j][1] = self.vert_list[line_list[0][j+1]][1]
                    ExtRingCoords[j][2] = self.vert_list[line_list[0][j+1]][2]
                Tessellator.AddRing(pointer(ExtRingCoords), c_int(int(line_list[0][0])), c_bool(1))
                #compute
                OutputVerNum = c_int(0)
                OutputIndiceNum = c_int(0)
                if Tessellator.Tessellation(byref(OutputVerNum), byref(OutputIndiceNum)) == c_bool(0):
                    print "Tesselation failed"
                #output
                OutputCoords = (c_double * 3 * OutputVerNum.value)()
                OutputIndices = (c_int * 3 * OutputIndiceNum.value)()
                Tessellator.Output(pointer(OutputCoords), pointer(OutputIndices))
                #convert indices
                if line_list[0][0] != OutputVerNum.value:
                    print ('intersection existed')
                OutputCoordsIndice = [] #the indices of the outputverts
                for j in range (0, OutputVerNum.value):
                    vert = [OutputCoords[j][0], OutputCoords[j][1], OutputCoords[j][2]]
                    try:
                        k = self.vert_list.index(vert)
                    except ValueError:
                        k = len(self.vert_list)
                        self.vert_list.append(vert)
                        print ('Vertex '+ str(k) + ' added')
                    OutputCoordsIndice.append(k)
                #Add to face_list
                for j in range (0, OutputIndiceNum.value):
                    self.face_list.append([OutputCoordsIndice[OutputIndices[j][0]],OutputCoordsIndice[OutputIndices[j][1]],OutputCoordsIndice[OutputIndices[j][2]]])
            else:
                self.face_list.append(line_list[0][1:])

        #check the content
        if self.vert_list.count == 0 or self.face_list.count == 0:
            print "Invalid Poly file!\n"
            sys.exit()
        f_poly.close()
        os.remove(self.InputFile + "mid")
    #end __ReadPoly


    def __WriteObj(self):
        try:
            f_obj = file(self.OutputFile, 'w')
        except:
            print ("Invalide file:" + self.OutputFile)
            sys.exit()
        
        f_obj.write("# Created by obj2poly from "+ str(self.InputFile) + '\n')
        f_obj.write("# Object\n")

        #vertices
        for vert in self.vert_list:
            f_obj.write("v ")
            f_obj.write(str(vert).replace(',', '')[1:-1] + '\n')
        f_obj.write("# ")
        f_obj.write(str(len(self.vert_list)) + ' ')
        f_obj.write("vertices\n")

        #faces
        for face in self.face_list:
            #index + 1
            face = [i + 1 for i in face]
            f_obj.write("f ")
            f_obj.write(str(face).replace(',', '')[1:-1] + '\n')
        f_obj.write("# ")
        f_obj.write(str(len(self.face_list)) + ' ')
        f_obj.write("faces\n")
        f_obj.close()
    #end __WriteObj


    def __WritePoly(self):
        try:
            f_poly = file(self.OutputFile, 'w')
        except:
            print ("Invalide file:" + self.OutputFile)
            sys.exit()
        f_poly.write(str(len(self.vert_list)) + ' 3'+ ' 0' + ' 0'+'\n')
        for i in range(0, len(self.vert_list)):
            f_poly.write(str(i) +' '+ str(self.vert_list[i]).replace(',', '')[1:-1] + '\n')

        #write faces
        f_poly.write(str(len(self.face_list)) + ' 0' + '\n')
        for i in range(0, len(self.face_list)):
            f_poly.write("1 0\n")
            f_poly.write(str(len(self.face_list[i])) + ' ')
            for j in range (0, len(self.face_list[i])):
                f_poly.write(str(self.face_list[i][j]) + ' ')
            f_poly.write('\n')
        f_poly.write('0\n')
        f_poly.write('0\n')
        f_poly.close()
    #end __WritePoly